#region File Header
//-----------------------------------------------------------------------------
// SibLib
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System;
using System.Globalization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace SibLib.GameState
{
    /// <summary>
    /// This is a more advanced MenuEntry type, allowing edition of a number (integer value).
    /// </summary>
    public class MenuEntryNumber : MenuEntry
    {
        #region Protected Members
        /// <summary>
        /// Current value.
        /// </summary>
        protected int m_Value;

        /// <summary>
        /// Minimum value.
        /// </summary>
        protected int m_Minimum;

        /// <summary>
        /// Maximum value.
        /// </summary>
        protected int m_Maximum;

        /// <summary>
        /// Amount of value change when required.
        /// </summary>
        protected int m_Step;
        #endregion

        /// <summary>
        /// Current value.
        /// </summary>
        /// <remarks>
        /// This property makes no checks on values, careful with setting.
        /// </remarks>
        public int Value
        {
            get { return m_Value; }
            set { m_Value = value; }
        }

        #region Events
        public event EventHandler<PlayerIndexEventArgs> ValueChanged;

        /// <summary>
        /// Method for raising the ValueChanged event.
        /// </summary>
        protected internal virtual void OnValueChanged(PlayerIndex playerIndex)
        {
            if (ValueChanged != null)
                ValueChanged(this, new PlayerIndexEventArgs(playerIndex));
        }
        #endregion

        #region Initialization

        /// <summary>
        /// Full setup constructor.
        /// </summary>
        /// <param name="text">Text of the entry (should include ':' or ' ')</param>
        /// <param name="minimum">Minimum value</param>
        /// <param name="maximum">Maximum value</param>
        /// <param name="step">Step increase</param>
        public MenuEntryNumber(string text, int minimum, int maximum, int step) :
            base(text)
        {
            m_Minimum = minimum;
            m_Maximum = maximum;
            m_Step = step;
            m_Value = minimum;
        }

        /// <summary>
        /// Default step of 1.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="minimum"></param>
        /// <param name="maximum"></param>
        public MenuEntryNumber(string text, int minimum, int maximum) :
            this(text, minimum, maximum, 1)
        {
        }

        /// <summary>
        /// Default minimum of 0 and step of 1.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="maximum"></param>
        public MenuEntryNumber(string text, int maximum) :
            this(text, 0, maximum, 1)
        {
        }

        #endregion

        #region Update

        /// <summary>
        /// Increase value by step.
        /// </summary>
        /// <param name="playerIndex"></param>
        protected internal override void OnSelectEntry(PlayerIndex playerIndex)
        {
            IncValue(playerIndex);

            base.OnSelectEntry(playerIndex);
        }

        /// <summary>
        /// Handle non-standard button input, including Left/Right, X, Plus/Minus.
        /// A is taken care of by OnSelectEntry().
        /// </summary>
        /// <param name="inputState">Current input state.</param>
        /// <param name="playerIndex">Controlling player index, only one checked.</param>
        protected internal override void OnCustomInput(InputState inputState, PlayerIndex playerIndex)
        {
            if (inputState.IsNewButtonPress(Buttons.LeftThumbstickLeft, playerIndex) ||
                inputState.IsNewButtonPress(Buttons.DPadLeft, playerIndex) ||
                //inputState.IsNewButtonPress(Buttons.X, playerIndex) ||
                inputState.IsNewKeyPress(Keys.Left, playerIndex) ||
                inputState.IsNewKeyPress(Keys.Subtract, playerIndex))
                DecValue(playerIndex);

            if (inputState.IsNewButtonPress(Buttons.LeftThumbstickRight, playerIndex) ||
                inputState.IsNewButtonPress(Buttons.DPadRight, playerIndex) ||
                //inputState.IsNewButtonPress(Buttons.A, playerIndex) ||
                inputState.IsNewKeyPress(Keys.Right, playerIndex) ||
                inputState.IsNewKeyPress(Keys.Add, playerIndex))
                IncValue(playerIndex);
            
            base.OnCustomInput(inputState, playerIndex);
        }

        protected void IncValue(PlayerIndex playerIndex)
        {
            int prevValue = m_Value;

            m_Value += m_Step;
            if (m_Value > m_Maximum)
                m_Value = m_Minimum;

            if (m_Value != prevValue)
                OnValueChanged(playerIndex);
        }

        protected void DecValue(PlayerIndex playerIndex)
        {
            int prevValue = m_Value;

            m_Value -= m_Step;
            if (m_Value < m_Minimum)
                m_Value = m_Maximum;

            if (m_Value != prevValue)
                OnValueChanged(playerIndex);
        }

        #endregion

        #region Render

        protected override void Draw(SpriteBatch spriteBatch, SpriteFont font, Vector2 position, Color color, float scale)
        {
            Vector2 origin = new Vector2(0, font.LineSpacing / 2);
            // TODO: this generates lots of garbage, might not care here.
            spriteBatch.DrawString(font, m_Text + m_Value.ToString(CultureInfo.InvariantCulture), position, color, 0, origin, scale, SpriteEffects.None, 0);
        }
        #endregion
    }
}